/**
 * OCR预处理服务
 * 使用Tesseract.js进行图片文字识别和清洗
 */

import Tesseract from 'tesseract.js';
import { AppError } from '../utils/appError.js';

// 支持的图片格式
const SUPPORTED_FORMATS = ['image/jpeg', 'image/jpg', 'image/png'];

// 最大图片大小（10MB）
const MAX_IMAGE_SIZE = 10 * 1024 * 1024;

// OCR超时时间（30秒）
const OCR_TIMEOUT = 30000;

/**
 * 验证图片格式
 * @param {Buffer} imageBuffer - 图片Buffer
 * @returns {string} MIME类型
 * @throws {AppError} 如果格式不支持
 */
const validateImageFormat = (imageBuffer) => {
  if (!imageBuffer || !Buffer.isBuffer(imageBuffer)) {
    throw new AppError('INVALID_INPUT', '无效的图片数据', 400);
  }

  // 检查图片魔数（文件头）
  const magic = imageBuffer.slice(0, 4).toString('hex');

  // JPEG: ffd8ff
  if (magic.startsWith('ffd8ff')) {
    return 'image/jpeg';
  }

  // PNG: 89504e47
  if (magic.startsWith('89504e47')) {
    return 'image/png';
  }

  throw new AppError('UNSUPPORTED_FORMAT', '仅支持JPEG和PNG格式的图片', 400);
};

/**
 * 验证图片大小
 * @param {Buffer} imageBuffer - 图片Buffer
 * @throws {AppError} 如果图片过大
 */
const validateImageSize = (imageBuffer) => {
  if (imageBuffer.length > MAX_IMAGE_SIZE) {
    throw new AppError(
      'IMAGE_TOO_LARGE',
      `图片大小不能超过${MAX_IMAGE_SIZE / 1024 / 1024}MB`,
      400
    );
  }
};

/**
 * 清洗和格式化OCR识别结果
 * @param {string} rawText - 原始识别文本
 * @param {number} confidence - 整体置信度
 * @returns {object} 清洗后的结果
 */
export const cleanOCRText = (rawText, confidence = 0) => {
  if (!rawText || typeof rawText !== 'string') {
    return {
      cleanedText: '',
      confidence: confidence,
      questionableSections: [],
      formattingPreserved: false,
    };
  }

  let cleanedText = rawText;

  // 1. 符号标准化：英文标点转中文标点
  const punctuationMap = {
    ',': '，',
    '.': '。',
    '!': '！',
    '?': '？',
    ':': '：',
    ';': '；',
    '(': '（',
    ')': '）',
    '"': '"',
    // 单引号转换由于语法问题单独处理
  };

  // 转换标点符号（但要保留数字中的点号）
  cleanedText = cleanedText.replace(/([^\d])\./g, '$1。');
  cleanedText = cleanedText.replace(/,(?!\d)/g, '，');
  cleanedText = cleanedText.replace(/!/g, '！');
  cleanedText = cleanedText.replace(/\?/g, '？');
  cleanedText = cleanedText.replace(/:/g, '：');
  cleanedText = cleanedText.replace(/;/g, '；');

  // 2. 常见OCR错误修正
  const commonErrors = [
    // 示例错误映射
    { pattern: /在来/g, replacement: '再来' },
    { pattern: /以经/g, replacement: '已经' },
    { pattern: /的的/g, replacement: '的' },
    { pattern: /了了/g, replacement: '了' },
  ];

  commonErrors.forEach(({ pattern, replacement }) => {
    cleanedText = cleanedText.replace(pattern, replacement);
  });

  // 3. 格式还原：保留段落结构
  // 移除多余的空格，但保留换行
  cleanedText = cleanedText.replace(/ +/g, ' ');
  
  // 确保段落之间有换行
  cleanedText = cleanedText.replace(/\n{3,}/g, '\n\n');
  
  // 移除行首尾空格
  cleanedText = cleanedText
    .split('\n')
    .map((line) => line.trim())
    .join('\n');

  // 4. 检测低置信度区域
  const questionableSections = [];
  
  // 如果整体置信度低于80%，标记整个文本
  if (confidence < 0.8) {
    questionableSections.push({
      position: '全文',
      confidence: confidence,
      note: '识别置信度较低，建议人工校对',
    });
  }

  return {
    cleanedText: cleanedText.trim(),
    confidence: confidence,
    questionableSections,
    formattingPreserved: true,
  };
};

/**
 * 图片预处理（可选功能）
 * @param {Buffer} imageBuffer - 图片Buffer
 * @returns {Promise<Buffer>} 预处理后的图片Buffer
 */
export const preprocessImage = async (imageBuffer) => {
  // 验证图片
  validateImageFormat(imageBuffer);
  validateImageSize(imageBuffer);

  // 注意：Tesseract.js会自动进行一些预处理
  // 这里可以添加额外的预处理逻辑（如使用sharp库）
  // 目前直接返回原始buffer
  
  return imageBuffer;
};

/**
 * 识别图片中的文字
 * @param {Buffer} imageBuffer - 图片Buffer
 * @returns {Promise<object>} 识别结果
 * @throws {AppError} 如果识别失败
 */
export const recognizeText = async (imageBuffer) => {
  try {
    // 1. 验证图片格式和大小
    const imageFormat = validateImageFormat(imageBuffer);
    validateImageSize(imageBuffer);

    // 2. 执行OCR识别
    console.log('开始OCR识别...');
    const startTime = Date.now();

    // 创建超时Promise
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => {
        reject(new AppError('OCR_TIMEOUT', 'OCR识别超时，请重试', 408));
      }, OCR_TIMEOUT);
    });

    // 执行Tesseract识别（支持中文）
    const recognizePromise = Tesseract.recognize(imageBuffer, 'chi_sim+eng', {
      logger: (info) => {
        // 可选：记录识别进度
        if (info.status === 'recognizing text') {
          console.log(`OCR进度: ${Math.round(info.progress * 100)}%`);
        }
      },
    });

    // 使用Promise.race实现超时控制
    const result = await Promise.race([recognizePromise, timeoutPromise]);

    const processingTime = Date.now() - startTime;
    console.log(`OCR识别完成，耗时: ${processingTime}ms`);

    // 3. 提取识别结果
    const rawText = result.data.text;
    const confidence = result.data.confidence / 100; // 转换为0-1范围

    // 4. 清洗和格式化文本
    const cleanedResult = cleanOCRText(rawText, confidence);

    // 5. 返回完整结果
    return {
      success: true,
      data: {
        text: cleanedResult.cleanedText,
        rawText: rawText,
        confidence: confidence,
        questionableSections: cleanedResult.questionableSections,
        metadata: {
          imageFormat: imageFormat,
          imageSize: imageBuffer.length,
          processingTime: processingTime,
          language: 'chi_sim+eng',
        },
      },
      message: '文字识别成功',
    };
  } catch (error) {
    console.error('OCR识别失败:', error);

    // 如果是AppError（操作错误），直接抛出
    if (error instanceof AppError || error.isOperational) {
      throw error;
    }

    // 其他错误包装为通用错误
    throw new AppError('OCR_FAILED', '文字识别失败，请重试', 500, error);
  }
};

/**
 * 批量识别多张图片（可选功能）
 * @param {Array<Buffer>} imageBuffers - 图片Buffer数组
 * @returns {Promise<Array<object>>} 识别结果数组
 */
export const recognizeMultiple = async (imageBuffers) => {
  if (!Array.isArray(imageBuffers) || imageBuffers.length === 0) {
    throw new AppError('INVALID_INPUT', '请提供至少一张图片', 400);
  }

  // 限制批量识别数量
  if (imageBuffers.length > 5) {
    throw new AppError('TOO_MANY_IMAGES', '一次最多识别5张图片', 400);
  }

  // 并行识别所有图片
  const results = await Promise.all(
    imageBuffers.map((buffer, index) =>
      recognizeText(buffer).catch((error) => ({
        success: false,
        index,
        error: error.message,
      }))
    )
  );

  return {
    success: true,
    data: results,
    message: `成功识别${results.filter((r) => r.success).length}/${results.length}张图片`,
  };
};

